﻿ using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using P2P.Client.Enums;
using P2P.Client.Model;
using P2P.Client.Tasks;
using P2P.Network.ExtensionMethods;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace P2P.Client.Handler
{
    public class NatCheckHandler
    {
        private static readonly object _lock = new object();
        private static bool _step1Success = false;

        private bool Step1Success 
        {
            get 
            {
                lock (_lock) 
                {
                    return _step1Success;
                }
            }
            set 
            {
                lock (_lock) 
                {
                   _step1Success = value;
                }
            }
        }
        
        private static bool _step3Success = false;

        private bool Step3Success
        {
            get
            {
                lock (_lock)
                {
                    return _step3Success;
                }
            }
            set
            {
                lock (_lock)
                {
                    _step3Success = value;
                }
            }
        }

        private static bool _step5Success = false;

        private bool Step5Success
        {
            get
            {
                lock (_lock)
                {
                    return _step5Success;
                }
            }
            set
            {
                lock (_lock)
                {
                    _step5Success = value;
                }
            }
        }

        private ApiProtocol apiProtocol;

        public NatCheckHandler(ApiProtocol apiProtocol)
        {
            this.apiProtocol = apiProtocol;
        }

        public void NatCheckFinished() 
        {
            int natType;
            int.TryParse(apiProtocol.Params["NatType"].ToString(), out natType);

            SharedModel.Instance.NatType = (NatType)natType;

            Step1Success = false;
            Step3Success = false;
            Step5Success = false;
        }

        public void Step1() 
        {
            Step1Success = true;
        }

        public void Step2()
        {
            int count = 60;
            Task.Run(async () => 
            {
                while (true) 
                {
                    if (Step1Success)
                    {
                        JObject data = new JObject();
                        data.Add("Name", "NatCheck");
                        data.Add("Method", "Step2");
                        data.Add("Version", "1.0");

                        JObject param = new JObject();
                        param.Add("AccountId", SharedModel.Instance.AccountId);
                        data.Add("Params", param);

                        string ack = JsonConvert.SerializeObject(R<JObject>.Ok(data));

                        apiProtocol.Socket.SendTo(ack, apiProtocol.RemoteEndPoint);
                        return;
                    }

                    if ((--count) == 0 && !Step1Success) 
                    {
                        JObject data = new JObject();
                        data.Add("Name", "NatCheck");
                        data.Add("Method", "Step3");
                        data.Add("Version", "1.0");

                        JObject param = new JObject();
                        param.Add("AccountId", SharedModel.Instance.AccountId);
                        data.Add("Params", param);

                        string ack = JsonConvert.SerializeObject(R<JObject>.Ok(data));

                        apiProtocol.Socket.SendTo(ack, apiProtocol.RemoteEndPoint);
                        return;
                    }

                    await Task.Delay(100);
                }
            });
        }

        public void Step3() 
        {
            Step3Success = true;
        }

        public void Step4() 
        {
            int count = 60;
            Task.Run(async () =>
            {
                while (true)
                {
                    if (Step3Success)
                    {
                        JObject data = new JObject();
                        data.Add("Name", "NatCheck");
                        data.Add("Method", "Step4");
                        data.Add("Version", "1.0");

                        JObject param = new JObject();
                        param.Add("AccountId", SharedModel.Instance.AccountId);
                        data.Add("Params", param);

                        string ack = JsonConvert.SerializeObject(R<JObject>.Ok(data));

                        apiProtocol.Socket.SendTo(ack, apiProtocol.RemoteEndPoint);
                        return;
                    }

                    if ((--count) == 0 && !Step3Success)
                    {
                        JObject data = new JObject();
                        data.Add("Name", "NatCheck");
                        data.Add("Method", "Step5");
                        data.Add("Version", "1.0");

                        JObject param = new JObject();
                        param.Add("AccountId", SharedModel.Instance.AccountId);
                        data.Add("Params", param);

                        string ack = JsonConvert.SerializeObject(R<JObject>.Ok(data));

                        apiProtocol.Socket.SendTo(ack, SharedModel.Instance.Hosts.UDPMainServerSecondPublicIP,
                            SharedModel.Instance.Hosts.UDPMainServerSecondPublicPort.Value);

                        apiProtocol.Socket.SendTo(ack, apiProtocol.RemoteEndPoint);
                        return;
                    }

                    await Task.Delay(100);
                }
            });
        }

        public void Step5() 
        {
            Step5Success = true;
        }

        public void Step6()
        {
            int count = 60;
            Task.Run(async () =>
            {
                while (true)
                {
                    if (Step5Success)
                    {
                        JObject data = new JObject();
                        data.Add("Name", "NatCheck");
                        data.Add("Method", "Step6");
                        data.Add("Version", "1.0");

                        JObject param = new JObject();
                        param.Add("AccountId", SharedModel.Instance.AccountId);
                        data.Add("Params", param);

                        string ack = JsonConvert.SerializeObject(R<JObject>.Ok(data));

                        apiProtocol.Socket.SendTo(ack, apiProtocol.RemoteEndPoint);
                        return;
                    }

                    if ((--count) == 0 && !Step5Success)
                    {
                        JObject data = new JObject();
                        data.Add("Name", "NatCheck");
                        data.Add("Method", "Step7");
                        data.Add("Version", "1.0");

                        JObject param = new JObject();
                        param.Add("AccountId", SharedModel.Instance.AccountId);
                        data.Add("Params", param);

                        string ack = JsonConvert.SerializeObject(R<JObject>.Ok(data));

                        apiProtocol.Socket.SendTo(ack, apiProtocol.RemoteEndPoint);
                        return;
                    }

                    await Task.Delay(100);
                }
            });
        }
    }
}
